#include "SPI.h"
#if defined (SPI0)

/* ********************************************************** */
/*!	
	\brief Writes and reads a 16-bit word via SPI.

	\note Selects hardware or software SPI based on constant
	 defintion SPI0_SOFT.

	\author Joe Pardue 
	\date October 29, 2010
	\version 1.00
*/
/* ********************************************************** */
uint16_t spi0_master_rw16(uint16_t to_slave)
{
	#if defined (SPI0_SOFT)
	return spi0_soft_master_rw16(to_slave);
	#else // HARD
	return spi0_hard_master_rw16(to_slave);
	#endif
}
/* ********************************************************** */
/*!	
	\brief Writes and reads a 16-bit word via software SPI
	for spi0.

	\note Selects hardware or software SPI based on constant
	 defintion SPI0_SOFT.

	\return 16-bit word from the slave device.

	\param to_slave - 16-bit word to send to the slave device.

	\author October 29, 2010 
	\date 9/22/10
	\version 1.00
*/
/* ********************************************************** */
uint16_t spi0_soft_master_rw16(uint16_t to_slave)
{
	uint16_t from_slave = 0;

	// Select the slave clear /SS to 0
	spi_soft_clear_ss();

	for(int i=0; i<=15; i++)
	{
		// Send a bit
		if(is_bit_set(to_slave,i))
			spi_soft_set_mosi_bit();
		else
			spi_soft_clear_mosi_bit();

		// Receive a bit
		// temp bits start 0 so change only if 1
		if (miso_port_pins & (1<<miso_port_pin))
			from_slave |= (1 << i);

   		// Toggle the clock
    	spi_soft_toggle_sclk();
	}

	// Deselect the slave set /SS to 1
	spi_soft_set_ss();
	
	return from_slave;
}



#elif defined (SPI0_HARD)
/* ********************************************************** */
/* ********************************************************** */
/*!	
	\brief Writes and reads a 16-bit word via hardware SPI
	for spi0.

	\note Blocks waiting for send to complete

	\return 16-bit word from the slave device.

	\param to_slave - 16-bit word to send to the slave device.

	\author Joe Pardue 
	\date October 29, 2010
	\version 1.00
*/
/* ********************************************************** */
uint16_t spi0_hard_master_rw16(uint16_t to_slave)
{
	uint8_t to_slave_low = (uint8_t) to_slave;
	uint8_t to_slave_high = (uint8_t) (to_slave >> 8);
	uint8_t from_slave_high = 0;
	uint8_t from_slave_low = 0;

	// select slave
	spi_hard_set_ss();

	// Put byte in SPI data register
	SPDR = to_slave_high;	

	// Poll SPIF-flag until transfer complete				
	while(!(SPSR & (1<<SPIF)));

	// Get the SPI data reg.
	from_slave_low = SPDR;

	// Put byte in SPI data register
	SPDR = to_slave_low;	

	// Poll SPIF-flag until transfer complete				
	while(!(SPSR & (1<<SPIF)));

	// Get the SPI data reg.
	from_slave_high = SPDR;
		
	// deselect slave
	spi_hard_clear_ss();

	return ( (uint16_t)(from_slave_high << 8) + (uint16_t)from_slave_low );						
}
#endif
